package com.spa.application.service.shop;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.spa.application.dto.shop.BusinessDataDTO;
import com.spa.application.query.shop.BusinessDataQuery;
import com.spa.domain.entity.Massagist;
import com.spa.domain.entity.OrderExt;
import com.spa.domain.entity.OrderInfo;
import com.spa.domain.service.MassagistService;
import com.spa.domain.service.OrderService;
import com.spa.domain.service.ShopService;
import com.spa.infrastructure.enums.dict.order.OrderOperStatusEnum;
import com.spa.infrastructure.enums.dict.order.OrderStatusEnum;
import com.spa.infrastructure.repository.condition.OrderInfoCondition;
import com.spa.infrastructure.util.DateUtil;
import com.spa.infrastructure.util.SessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ShopBusinessDataService {

    @Autowired
    private ShopService shopService;

    @Autowired
    private MassagistService massagistService;

    @Autowired
    private OrderService orderService;

    public BusinessDataDTO index(BusinessDataQuery query) throws ParseException {
        BusinessDataDTO businessDataDTO = new BusinessDataDTO();
        Date date = DateUtil.str2Date(query.getDate(), "yyyy-MM-dd");
        String beginDate = DateUtil.date2Str(DateUtil.getStartTimeOfCurrentDay(date));
        String endDate = DateUtil.date2Str(DateUtil.getEndTimeOfCurrentDay(date));
        //1、获取门店下的技师
        Long shopId = SessionUtil.getUser().getShopId();
        List<Massagist> massagists = massagistService.getMassagistListByShopId(shopId);
        OrderInfoCondition orderInfoCondition = new OrderInfoCondition();
        orderInfoCondition.setBeginDate(beginDate);
        orderInfoCondition.setEndDate(endDate);
        orderInfoCondition.setShopId(shopId);
        List<OrderInfo> orderInfos = orderService.orderList(orderInfoCondition);
        //指定日期门店下技师所有的订单
        //进行中和已完成的订单列表
        List<OrderInfo> inServiceOrders = orderInfos.stream()
                .filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$40.getCode()))
                .toList();
        //已取消订单（技师已出发或已到达）
        List<OrderInfo> cancel = orderInfos.stream().filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$99.getCode())
                && (Objects.equals(orderInfo.getOrderOperStatus(), OrderOperStatusEnum.$20.getCode())
                || Objects.equals(orderInfo.getOrderOperStatus(), OrderOperStatusEnum.$30.getCode()))).toList();
        List<OrderInfo> cancelOrders = orderInfos.stream()
                .filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$99.getCode()))
                .toList();
        //获取已完成用户数
        long userCount = inServiceOrders.stream().map(OrderInfo::getUserId).toList().stream().distinct().count();
        long userAlreadyCount = inServiceOrders.stream().filter(o -> Objects.equals(o.getStatus(), OrderStatusEnum.$40.getCode())).map(OrderInfo::getUserId).toList().stream().distinct().count();
        //获取服务中用户数
        long userInServiceCount = orderInfos.stream().filter(o -> Objects.equals(o.getStatus(), OrderStatusEnum.$30.getCode())).map(OrderInfo::getUserId).toList().stream().distinct().count();
        long userCancelCount = cancelOrders.stream().map(OrderInfo::getUserId).toList().stream().distinct().count();
        long massgistCount = inServiceOrders.stream().map(OrderInfo::getMassagistId).toList().stream().distinct().count();
        int performance = inServiceOrders.stream().mapToInt(OrderInfo::getOrderPrice).sum();
        int performanceExt = inServiceOrders.stream().mapToInt(OrderInfo::getExtTotalPrice).sum();
        int performanceCancel = cancel.stream().mapToInt(OrderInfo::getTravelPrice).sum();
        businessDataDTO.setInServicePeoples(userInServiceCount);
        businessDataDTO.setPerformance(performance + performanceExt + performanceCancel);
        if (massgistCount != 0) {
            businessDataDTO.setAvgPerformance((int) ((performance + performanceExt + performanceCancel) / userCount));
        }
        //3、待接单人数 + 服务人数 + 取消人数 = 下单人数
        int extraTimePeoples = inServiceOrders.stream().filter(orderInfo -> orderInfo.getOrderExtList() != null)
                .map(orderInfo -> {
                    AtomicInteger total = new AtomicInteger();
                    orderInfo.getOrderExtList().forEach(orderExt -> {
                        total.addAndGet(orderExt.getOrderCount());
                    });
                    return total.get();
                }).reduce(Integer::sum).orElse(0);
        businessDataDTO.setCancelPeoples(userCancelCount);
        businessDataDTO.setBuyPeoples(userAlreadyCount);
        businessDataDTO.setExtraTimePeoples(extraTimePeoples);
        //榜单数据
        Map<Long, List<Massagist>> id2MassagistMap = massagists.stream().collect(Collectors.groupingBy(Massagist::getId));
        Map<Long, List<Integer>> massagistId2Performance = inServiceOrders.stream()
                .collect(Collectors.groupingBy(OrderInfo::getMassagistId, Collectors.mapping(OrderInfo::getOrderPrice, Collectors.toList())));
        Map<Long, List<Integer>> massagistId2PerformanceCancel = cancel.stream()
                .collect(Collectors.groupingBy(OrderInfo::getMassagistId, Collectors.mapping(OrderInfo::getTravelPrice, Collectors.toList())));
        Map<Long, List<List<OrderExt>>> massagistId2OrderExts = inServiceOrders.stream().collect(Collectors.groupingBy(OrderInfo::getMassagistId, Collectors.mapping(OrderInfo::getOrderExtList, Collectors.toList())));
        List<BusinessDataDTO.LeaderBoard> performanceLeaderBoard = new ArrayList<>();
        List<BusinessDataDTO.LeaderBoard> extraTimeLeaderBoard = new ArrayList<>();
        massagistId2Performance.forEach((id, list) -> {
            BusinessDataDTO.LeaderBoard leaderBoard = new BusinessDataDTO.LeaderBoard();
            if (ObjectUtil.isNotNull(id2MassagistMap.get(id))) {
                Massagist massagist = id2MassagistMap.get(id).stream().findFirst().get();
                if (ObjectUtil.isNotNull(massagist)) {
                    leaderBoard.setName(massagist.getName());
                    leaderBoard.setHeadIcon(massagist.getWorkPhoto());
                    List<List<OrderExt>> extList = massagistId2OrderExts.get(massagist.getId());
                    AtomicInteger totalPrice = new AtomicInteger();
                    extList.forEach(sublist -> {
                        if (ObjectUtil.isNotNull(sublist)) {
                            sublist.forEach(orderExt -> totalPrice.addAndGet(orderExt.getOrderPrice()));
                        }
                    });
                    int cancelPrice = 0;
                    if (CollectionUtil.isNotEmpty(massagistId2PerformanceCancel.get(id))) {
                        cancelPrice = massagistId2PerformanceCancel.get(id).stream().reduce(Integer::sum).orElse(0);
                    }
                    leaderBoard.setPerformance(list.stream().reduce(Integer::sum).orElse(0) + totalPrice.get() + cancelPrice);
                    performanceLeaderBoard.add(leaderBoard);
                }
            }
        });
        massagistId2OrderExts.forEach((id, list) -> {
            BusinessDataDTO.LeaderBoard leaderBoard = new BusinessDataDTO.LeaderBoard();
            if (ObjectUtil.isNotNull(id2MassagistMap.get(id))) {
                Massagist massagist = id2MassagistMap.get(id).stream().findFirst().get();
                if (ObjectUtil.isNotNull(massagist)) {
                    leaderBoard.setName(massagist.getName());
                    leaderBoard.setHeadIcon(massagist.getWorkPhoto());
                    AtomicInteger totalPrice = new AtomicInteger();
                    list.forEach(sublist -> {
                        if (ObjectUtil.isNotNull(sublist)) {
                            sublist.forEach(orderExt -> totalPrice.addAndGet(orderExt.getOrderCount()));
                        }
                    });
                    leaderBoard.setPerformance(totalPrice.get());
                    extraTimeLeaderBoard.add(leaderBoard);
                }
            }
        });
        Comparator<BusinessDataDTO.LeaderBoard> comparator = Comparator.comparing(BusinessDataDTO.LeaderBoard::getPerformance).reversed();
        performanceLeaderBoard.sort(comparator);
        extraTimeLeaderBoard.sort(comparator);
        businessDataDTO.setPerformanceLeaderBoard(performanceLeaderBoard.stream().limit(10).toList());
        businessDataDTO.setExtraTimeLeaderBoard(extraTimeLeaderBoard.stream().limit(10).toList());
        return businessDataDTO;
    }
}
